package me.linczh.bank.service;

import java.util.Date;
import java.util.List;

import me.linczh.bank.bean.AccountBean;
import me.linczh.bank.bean.AccountStatisticBean;
import me.linczh.bank.bean.OperatorBean;
import me.linczh.bank.bean.enums.AccountType;
import me.linczh.bank.bean.enums.DepositType;
import me.linczh.bank.bean.enums.ResultType;
import me.linczh.bank.dao.AccountDao;
import me.linczh.bank.dao.AccountStatisticDao;
import me.linczh.bank.dao.DaoFactory;
import me.linczh.framework.query.Query;

public class AccountService {
	private AccountDao accountDao = DaoFactory.getAccountDao();
	private AccountStatisticDao statisticDao = DaoFactory.getAccountStatisticDao();

	public AccountBean create(String identity, String username, String password,
			double balance, AccountType accounttype, DepositType deposittype) {
		if (balance < 0) return null;
		if (accounttype == AccountType.PERSONAL_VIP)
			if (balance < 1000000) return null;
		if (accounttype == AccountType.ENTERPRISE) {
			List<AccountBean> list = getEnterpriseAccounts(identity);
			if (list.size() == 0 && balance < 10000) return null;
		}
		AccountBean account = new AccountBean();
		account.setIdentity(identity);
		account.setUsername(username);
		account.setPassword(password);
		account.setBalance(balance);
		account.setFrozen(false);
		account.setAccounttype(accounttype);
		account.setDeposittype(deposittype);
		account = accountDao.create(account);
		if (accounttype == AccountType.PERSONAL_VIP) {
			AccountStatisticBean statistic = new AccountStatisticBean();
			statistic.setAccount(account.getAccount());
			statistic.setBalance(balance);
			statistic.setNumday(0);
			statistic.setChargemonth(0);
			statistic.setOverdrawtime(null);
			statisticDao.create(statistic);
		}
		return account;
	}
	
	public boolean deposit(AccountBean account, double money) {
		if (account != null) {
			account.setBalance(account.getBalance() + money);
			accountDao.update(account);
			return true;
		}
		return false;
	}
	
	public boolean withdrawal(AccountBean account, double money) {
		if (account != null) {
			if (account.getFrozen()) return false;
			double balance = account.getBalance();
			if (canDrawal(account, money)) {
				account.setBalance(balance - money);
				if (account.getAccounttype() == AccountType.PERSONAL_VIP)
					if (account.getBalance() < 0) {
						AccountStatisticBean statistic = statisticDao.findByAccount(account.getAccount());
						if (statistic.getOverdrawtime() == null)
							statistic.setOverdrawtime(new Date());
					}
				accountDao.update(account);
				return true;
			}
		}
		return false;
	}
	
	public ResultType transfer(AccountBean fromAccount, AccountBean toAccount, double money) {
		if (fromAccount != null && toAccount != null) {
			if (fromAccount.getFrozen()) return ResultType.FAIL_TO_DELETE;
			if (fromAccount.getAccounttype() == AccountType.ENTERPRISE || toAccount.getAccounttype() == AccountType.ENTERPRISE) {	// one of the account is enterprise
				if (toAccount.getAccounttype() != fromAccount.getAccounttype()) {
					// can not transfer between enterprise and person
					return ResultType.INVALID_TRANSFER_CUSTOMER_TYPE;
				}
			} else {
				if (fromAccount.getAccounttype() == AccountType.PERSONAL_COMMON) {	// transfer out account is common user
					if (!fromAccount.getIdentity().equals(toAccount.getIdentity())) {
						// common user can not transfer out to other user
						return ResultType.INVALID_TRANSFER_CUSTOMER_TYPE;
					}
				}
			}
			double fromBalance = fromAccount.getBalance();
			if (canDrawal(fromAccount, money)) {
				fromAccount.setBalance(fromBalance - money);
				toAccount.setBalance(toAccount.getBalance() + money);
				if (fromAccount.getAccounttype() == AccountType.PERSONAL_VIP)
					if (fromAccount.getBalance() < 0) {
						AccountStatisticBean statistic = statisticDao.findByAccount(fromAccount.getAccount());
						if (statistic.getOverdrawtime() == null)
							statistic.setOverdrawtime(new Date());
					}
				if (accountDao.update(fromAccount) && accountDao.update(toAccount)) return ResultType.SUCCESS;
			}
		}
		return ResultType.INSUFFICIENT_BALANCE;
	}
	
	public AccountBean changePassword(AccountBean account, String password) {
		if (account != null) {
			account.setPassword(password);
			if (accountDao.update(account)) return account;
		}
		return null;
	}
	
	public boolean deleteAccount(AccountBean account) {
		if (account != null) {
			if (accountDao.delete(account)) return true;
		}
		return false;
	}
	
	public boolean canDrawal(AccountBean account, double money) {
		if (account.getAccounttype() == AccountType.PERSONAL_COMMON) return account.getBalance() > money;
		else if (account.getAccounttype() == AccountType.PERSONAL_VIP) return account.getBalance() + 100000 > money;
		else {
			List<AccountBean> list = getEnterpriseAccounts(account.getIdentity());
			double total = 0;
			for (AccountBean a : list) {
				total += a.getBalance();
			}
			if (total - 10000 > money) return true;
		}
		return false;
	}
	
	public List<AccountBean> getEnterpriseAccounts(final String enterprise) {
		return accountDao.query(new Query<AccountBean>() {
			String identity = enterprise;
			@Override
			public boolean matched(AccountBean item) {
				// TODO Auto-generated method stub
				if (item.getIdentity().equals(identity) && item.getAccounttype() == AccountType.ENTERPRISE) return true;
				return false;
			}
			@Override
			public String statement() {
				// TODO Auto-generated method stub
				return "select * from account_tbl where" +
						"identity='" + identity + "' and " +
						"accounttype='" + AccountType.ENTERPRISE + "'";
			}
		});
	}
	
	public AccountBean getAccountByIdAndPassword(String account, String password) {
		AccountBean accountBean = accountDao.findById(account);
		if (accountBean != null) {
			if (accountBean.getPassword().equals(password)) return accountBean;
		}
		return null;
	}
	
	public AccountBean getAccountByOperator(OperatorBean operator) {
		return accountDao.findById(operator.getAccount());
	}
	
	public AccountBean getAccountById(String account) {
		return accountDao.findById(account);
	}
}
